package com.freely.data.services

import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.content.Intent
import android.location.LocationManager
import android.os.IBinder
import android.util.Log
import com.baidu.location.BDAbstractLocationListener
import com.baidu.location.BDLocation
import com.baidu.location.LocationClientOption
import com.freely.data.database.FreelyDatabase
import com.freely.data.entities.ChatRecord
import com.freely.data.entities.Group
import com.freely.data.entities.UserGroupRelation
import com.freely.data.managerUtils.FreelySharedPreferences
import com.freely.data.network.FreelyClient
import com.freely.data.network.ServerException
import com.freely.data.network.requestEntities.RQQueryMemberInformation
import com.freely.data.network.requestEntities.RQUserLocation
import com.freely.data.network.webSocket.MessageListener
import com.freely.data.repository.entities.GroupChatMessage
import com.freely.data.rxBus.RxBus
import com.freely.ui.service.MapService
import com.freely.ui.util.ErrorUtil
import com.google.gson.JsonElement
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.subjects.PublishSubject

const val GROUP_CHAT_MESSAGE = 3
const val ADD_NEW_GROUP = 17
const val MAP_LOCATION = 30

class FreelyService : Service() {
    private val TAG = "FreelyService"
    private var mapService: MapService? = null
    private lateinit var locationManager: LocationManager
    private lateinit var locationType: String
    private val messageListener = MessageListener { type, data: JsonElement ->
        Log.d(TAG, "socket: type=$type,data=$data")
        var result = false
        when (type) {
            GROUP_CHAT_MESSAGE -> {
                result = true
                receiveMessage(data)
            }
            ADD_NEW_GROUP -> {
                result = true
                addNewGroup(data)
            }
        }
        return@MessageListener result
    }
    private val disposables = CompositeDisposable()
    private val mapListener = object : BDAbstractLocationListener() {
        @SuppressLint("MissingPermission")
        override fun onReceiveLocation(p0: BDLocation) {
            val value = StringBuffer()
            value.append("经度：${p0.latitude}\n")
            value.append("纬度：${p0.longitude}\n")
            val temp = when (p0.locType) {
                BDLocation.TypeGpsLocation -> "GPS"
                BDLocation.TypeNetWorkLocation -> "网络"
                else -> "${p0.locType},${p0.locTypeDescription}"
            }
            value.append("定位方式：$temp\n")
            value.append("国家：${p0.country}\n")
            value.append("省：${p0.province}\n")
            value.append("市：${p0.city}\n")
            value.append("区：${p0.district}\n")
            value.append("街道：${p0.street}\n")
            Log.d(TAG, "onReceiveLocation:\n $value")
            if (p0.locType == 167) {
                val location = locationManager.getLastKnownLocation(locationType)
                p0.latitude = location.latitude
                p0.longitude = location.longitude
            }
            RxBus.instance.post(MAP_LOCATION, p0)
        }
    }

    override fun onBind(intent: Intent): IBinder {
        TODO("Return the communication channel to the service.")
    }

    override fun onCreate() {
        Log.d(TAG, "onCreate: 正在开启服务...")
        //rx bus 注册聊天消息发布者
        RxBus.instance.register(GROUP_CHAT_MESSAGE, PublishSubject.create<Any>().toSerialized())
        //rx bus 注册新群消息发布者
        RxBus.instance.register(ADD_NEW_GROUP, PublishSubject.create<Any>().toSerialized())
        //连接webSocket
        FreelyClient.connectionWebSocket();
        FreelyClient.getWebSocketManager().addListener(messageListener)
        mapInit()
        val disposable = RxBus.instance.toObservable(MAP_LOCATION, BDLocation::class.java)
                .subscribe({
                    val message = RQUserLocation(
                            FreelySharedPreferences.getInstance().userId,
                            it.latitude,
                            it.longitude
                    )
                    FreelyClient.send(FreelyClient.getGson().toJson(message))
                }, { ErrorUtil.errorHint(it) })
        disposables.add(disposable)
    }

    private fun mapInit() {
        Log.d(TAG, "mapInit: 注册位置发布者")
        RxBus.instance.register(MAP_LOCATION, PublishSubject.create<Any>().toSerialized())
        locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
        val list = locationManager.getProviders(true)
        if (list.contains(LocationManager.GPS_PROVIDER)){
            locationType = LocationManager.GPS_PROVIDER
        }else if (list.contains(LocationManager.NETWORK_PROVIDER)) {
            locationType = LocationManager.NETWORK_PROVIDER
        }

        mapService = MapService(applicationContext)
        val locationOption = LocationClientOption()
        locationOption.locationMode = LocationClientOption.LocationMode.Hight_Accuracy
        //可选，默认高精度，设置定位模式，高精度，低功耗，仅设备
        locationOption.openGps = true
        //可选，默认false，设置是否开启Gps定位
        locationOption.coorType = BDLocation.BDLOCATION_GCJ02_TO_BD09LL
        //可选，默认gcj02，设置返回的定位结果坐标系，如果配合百度地图使用，建议设置为bd09ll;
        locationOption.scanSpan = 5000
        //可选，默认0，即仅定位一次，设置发起连续定位请求的间隔需要大于等于1000ms才是有效的
        locationOption.setIsNeedAddress(true)
        //可选，设置是否需要地址信息，默认不需要
        locationOption.setIsNeedLocationDescribe(true)
        //可选，设置是否需要地址描述
        locationOption.setNeedDeviceDirect(false)
        //可选，设置是否需要设备方向结果
        locationOption.isLocationNotify = true
        //可选，默认false，设置是否当gps有效时按照1S1次频率输出GPS结果
        locationOption.setIgnoreKillProcess(false)
        //可选，默认true，定位SDK内部是一个SERVICE，并放到了独立进程，设置是否在stop的时候杀死这个进程，默认不杀死
        locationOption.setIsNeedLocationDescribe(true)
        //可选，默认false，设置是否需要位置语义化结果，可以在BDLocation.getLocationDescribe里得到，结果类似于“在北京天安门附近”
        locationOption.setIsNeedLocationPoiList(true)
        //可选，默认false，设置是否需要POI结果，可以在BDLocation.getPoiList里得到
        locationOption.SetIgnoreCacheException(false)
        //可选，默认false，设置是否收集CRASH信息，默认收集
        locationOption.setIsNeedAltitude(false)
        //可选，默认false，设置定位时是否需要海拔信息，默认不需要，除基础定位版本都可用
        locationOption.setEnableSimulateGps(true);
        //可选，设置是否需要过滤GPS仿真结果，默认需要，即参数为false
        mapService?.setLocationOption(locationOption)
        mapService?.registerListener(mapListener)
        mapService?.start()
    }

    private fun receiveMessage(data: JsonElement) {
        val chatRecord: ChatRecord = FreelyClient.getGson().fromJson(data, ChatRecord::class.java)
        FreelyDatabase.getInstance().userDAO().queryUserByUserId(chatRecord.userId)
                .onErrorResumeNext {
                    val requestMemberInformationArgs = RQQueryMemberInformation()
                    requestMemberInformationArgs.groupId = chatRecord.groupId
                    requestMemberInformationArgs.userId = chatRecord.userId
                    return@onErrorResumeNext FreelyClient.getFreelyService()
                            .queryMemberInformation(requestMemberInformationArgs)
                            .map {
                                if (!it.isResult) throw ServerException(it.failure)
                                FreelyDatabase.getInstance().userDAO().insertUser(it.success)
                                return@map it.success
                            }
                }.map {
                    FreelyDatabase.getInstance().chatRecordDAO().insertChatRecord(chatRecord)
                    val message = GroupChatMessage()
                    message.userName = it.userName
                    message.recordId = chatRecord.recordId
                    message.message = chatRecord.recordContent
                    message.time = chatRecord.recordSendTime
                    message.userHeadIcon = it.userImage
                    return@map message
                }.subscribe({
                    RxBus.instance.post(GROUP_CHAT_MESSAGE, it)
                }, { ErrorUtil.errorHint(it) }).dispose()
    }

    private fun addNewGroup(data: JsonElement) {
        Log.d(TAG, "addNewGroup: 收到新群")
        val group = FreelyClient.getGson().fromJson(data, Group::class.java)
        FreelyDatabase.getInstance().groupDAO().insertGroup(group)
        val userGroupRecord = UserGroupRelation()
        userGroupRecord.groupId = group.groupId
        userGroupRecord.userId = FreelySharedPreferences.getInstance().userId
        FreelyDatabase.getInstance().userGroupRelationDAO().insertUserGroupRelation(userGroupRecord)
        RxBus.instance.post(ADD_NEW_GROUP, group)
    }

    override fun onDestroy() {
        mapService?.stop()
        FreelyClient.getWebSocketManager().clearAll()
        RxBus.instance.cancellation(GROUP_CHAT_MESSAGE)
        RxBus.instance.cancellation(MAP_LOCATION)
    }
}

